package com.zhou.system.management.security.session;

import com.zhou.system.management.security.EvictEvent;
import com.zhou.system.management.util.ServletUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import java.util.Comparator;
import java.util.List;

/**
 * @author xianfeng
 * @date 2023/5/14 1:55
 */
@Component
public class MyConcurrentSessionControlAuthenticationStrategy extends ConcurrentSessionControlAuthenticationStrategy {
    /**
     * @param sessionRegistry the session registry which should be updated when the
     * authenticated session is changed.
     */
    private boolean myExceptionIfMaximumExceeded = false;

    @Autowired
    private WebApplicationContext applicationContext;

    public MyConcurrentSessionControlAuthenticationStrategy(SessionRegistry sessionRegistry) {
        super(sessionRegistry);
        super.setMaximumSessions(5);
        super.setExceptionIfMaximumExceeded(false);
    }

    @Override
    protected void allowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions,
                                             SessionRegistry registry) throws SessionAuthenticationException {
        if (myExceptionIfMaximumExceeded || (sessions == null)) {
            throw new SessionAuthenticationException(
                    this.messages.getMessage("ConcurrentSessionControlAuthenticationStrategy.exceededAllowed",
                            new Object[]{allowableSessions}, "Maximum sessions of {0} for this principal exceeded"));
        }
        // Determine least recently used sessions, and mark them for invalidation
        sessions.sort(Comparator.comparing(SessionInformation::getLastRequest));
        int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
        List<SessionInformation> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);

        for (SessionInformation session : sessionsToBeExpired) {
            session.expireNow();
            ;
            EvictEvent evictEvent = new EvictEvent();
            evictEvent.setSessionId(session.getSessionId());
            evictEvent.setPrincipal(session.getPrincipal());
            evictEvent.setKickSessionId(ServletUtil.getRequest().getRequestedSessionId());
            //applicationContext.publishEvent(evictEvent);
            //todo 并策略器
        }
    }
}
